﻿using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace google
{
    public class ClosureCompiler
    {
        public enum RequestType { js_code, code_url };
        public enum OutputFormat { xml, json, text};
        public enum CompilationLevel {WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, ADVANCED_OPTIMIZATIONS };
        public enum OutputInfo { compiled_code, warnings, errors, statistics };
        public enum WarningLevel { QUIET, DEFAULT, VERBOSE };

        public string _outFileName = null;
        public OutputFormat _outFormat = OutputFormat.text;

        public ClosureCompiler(List<FileInfo> files, string temp_file, string Out, OutputFormat Format, WarningLevel WarningLevel, CompilationLevel CompilationLevel, List<OutputInfo> OutputInfos, string ExternsJS, bool Pretty)
        {
            _outFileName = Out;
            _outFormat = Format;

            StringBuilder parms = new StringBuilder();
            parms.Append(String.Format(@"compilation_level={0}", CompilationLevel.ToString()));            
            parms.Append(String.Format(@"&output_format={0}", Format.ToString()));
            parms.Append(@"&output_file_name=" + temp_file);
            parms.Append(String.Format(@"&warning_level={0}", WarningLevel.ToString()));
            if (Pretty)
            {
                parms.Append(@"&formatting=pretty_print");
                parms.Append(@"&formatting=print_input_delimiter");
            }

            foreach(OutputInfo oi in OutputInfos )
                parms.Append(String.Format(@"&output_info={0}", oi.ToString()));

            if (!String.IsNullOrEmpty(ExternsJS))
            {
                parms.Append(@"&js_externs=");
                using (StreamReader reader = new StreamReader(ExternsJS))
                {
                    parms.Append(System.Web.HttpUtility.UrlEncode(reader.ReadToEnd()));
                }

            }

            parms.Append(@"&js_code=");

            foreach (FileInfo file in files)
            {
                using (StreamReader reader = new StreamReader(file.FullName))
                {
                    parms.Append(System.Web.HttpUtility.UrlEncode(reader.ReadToEnd()));
                }
            }



            using (StreamWriter f = new StreamWriter(Out))
            {
                try
                {
                    RunPost(parms.ToString(), f);
                }
                catch { }
                finally
                {
                    f.Flush();
                }

            }
        }

        void RunPost(String Parms, StreamWriter Out)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://closure-compiler.appspot.com/compile");
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            request.ContentLength = getBytesLength(Parms);

            StreamWriter postStream = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
            postStream.Write(Parms);
            postStream.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader stIn = new StreamReader(response.GetResponseStream());
            Out.Write(stIn.ReadToEnd());
            stIn.Close();

            response.Close();

            if (_outFormat == OutputFormat.xml)
            {
                XmlNode node = this.Xml.SelectSingleNode("/compilationResult/compiledCode");

                FileInfo f = new FileInfo(_outFileName);

                string filepath = Path.Combine(Path.GetFullPath(f.FullName), Path.GetFileNameWithoutExtension(f.FullName) + ".js");
                using (StreamWriter writer = new StreamWriter(filepath))
                {
                    writer.Write(node.InnerText);
                }
            }

        }

        long getBytesLength(string Parms)
        {
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] data = encoding.GetBytes(Parms.ToString());

            return data.Length;

        }

        public XmlDocument Xml
        {

            get
            {
                if (_outFormat != OutputFormat.xml)
                    throw new Exception("Expected OutputFormat xml, can't return Xml");

                XmlDocument xml = new XmlDocument();
                xml.Load(_outFileName);
                return xml;
            }
        }
    }
}
